package fr.kotton.myorganizer.task.adapter;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.support.v7.app.ActionBarActivity;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import fr.kotton.myorganizer.R;
import fr.kotton.myorganizer.bean.Task;
import fr.kotton.myorganizer.bean.TaskGroup;
import fr.kotton.myorganizer.db.MyOrganizerDbContract;
import fr.kotton.myorganizer.task.interfaces.TasksQueryCompleteListener;
import fr.kotton.myorganizer.utils.EndDateComparator;
import fr.kotton.myorganizer.utils.animation.DisplayNextView;
import fr.kotton.myorganizer.utils.animation.Flip3d;
import fr.kotton.myorganizer.utils.sql.DatabaseRemover;
import fr.kotton.myorganizer.utils.sql.SqlReadQuery;

public class TasksListAdapter extends ArrayAdapter<Task> {

    private static final int TYPE_ITEM = 0;
    private static final int TYPE_SEPARATOR = 1;

    private Context mContext;
    private LayoutInflater mLayoutInflater;

    // Contient la liste des tâches et des headers
    private ArrayList<Object> mListViewObjectsList = new ArrayList<Object>();

    // Contient la liste des groupes de tâches
    private LinkedList<TaskGroup> mTaskGroupsList = new LinkedList<TaskGroup>();

    // Liste des positions sélectionnées en mode CAB
    private ArrayList<Boolean> mCheckList = new ArrayList<Boolean>();

    // Objets utilisés pour gérer le CAB
    private ActionMode mActionMode;
    private ActionMode.Callback mActionModeCallBack;

    private TasksQueryCompleteListener mDbQueryCompletedListener;

    public TasksListAdapter(Context pContext, int pViewResourceId, TasksQueryCompleteListener pDbQueryCompletedListener) {
        super(pContext, pViewResourceId);

        mContext = pContext;

        mDbQueryCompletedListener = pDbQueryCompletedListener;

        mLayoutInflater = (LayoutInflater) pContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        mActionModeCallBack = new ActionMode.Callback() {

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.delete:
                        ArrayList<Boolean> lCheckList = new ArrayList<Boolean>(mCheckList);
                        ArrayList<Integer> lSelectedPositions = new ArrayList<Integer>();
                        for (int i = 0; i < lCheckList.size(); i++) {
                            if (lCheckList.get(i)) {
                                lSelectedPositions.add(i);
                            }
                        }
                        deleteMultipleTasks(lSelectedPositions);
                        mActionMode = null;
                        mode.finish(); // Action picked, so close the CAB
                        return true;
                    default:
                        return false;
                }
            }

            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                mode.getMenuInflater().inflate(R.menu.fragment_tasks_action_bar_delete_selection, menu);
                return true;
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
                // Reinitialize all entry to false
                mCheckList = new ArrayList<Boolean>(Collections.nCopies(mCheckList.size(), false));
                notifyDataSetChanged();
                mActionMode = null;
            }

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false;
            }

        };
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public int getItemViewType(int position) {
        if (mListViewObjectsList.get(position) instanceof Task) {
            return TYPE_ITEM;
        } else {
            return TYPE_SEPARATOR;
        }
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getCount() {
        return mListViewObjectsList.size();
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public Task getItem(int pPosition) {
        if (mListViewObjectsList.get(pPosition) instanceof Task) {
            return (Task) mListViewObjectsList.get(pPosition);
        }

        return null;
    }

    @Override
    public boolean isEnabled(int position) {
        return getItemViewType(position) == TYPE_ITEM;
    }

    @Override
    public View getView(final int pPosition, View convertView, ViewGroup parent) {
        final ViewHolder lHolder;
        int rowType = getItemViewType(pPosition);

        if (convertView == null) {
            lHolder = new ViewHolder();
            switch (rowType) {
                case TYPE_ITEM:
                    convertView = mLayoutInflater.inflate(R.layout.fragment_tasks_listview_entry, null);
                    lHolder.mTextViewTitle = (TextView) convertView.findViewById(R.id.textTitle);
                    lHolder.mTextViewTime = (TextView) convertView.findViewById(R.id.textTime);
                    lHolder.mCheckBoxUncheckedView = (CheckedTextView) convertView.findViewById(R.id.taskListCheckbox);
                    lHolder.mCheckBoxCheckedView = (ImageView) convertView.findViewById(R.id.taskListCheckboxImage);
                    break;
                case TYPE_SEPARATOR:
                    convertView = mLayoutInflater.inflate(R.layout.fragment_tasks_listview_separator, null);
                    lHolder.mTextViewTitle = (TextView) convertView.findViewById(R.id.textSeparator);
                    break;
            }
            convertView.setTag(lHolder);

        } else {
            lHolder = (ViewHolder) convertView.getTag();
        }

        switch (rowType) {
            case TYPE_ITEM:

                final Task lTask = (Task) mListViewObjectsList.get(pPosition);

                View.OnClickListener lCheckBoxOnClickListener = new View.OnClickListener() {

                    @Override
                    public void onClick(View pView) {

                        if (!mCheckList.get(pPosition)) {
                            mCheckList.set(pPosition, true);

                            setCheckedBoxVisibility(true, lHolder);
                            // applyRotation(true, lHolder.mCheckBoxUncheckedView, lHolder.mCheckBoxCheckedView, 0, -90);

                            // Must be placed after the mChecklist.add to have the good item count
                            if (mActionMode == null) {
                                mActionMode = ((ActionBarActivity) mContext).startActionMode(mActionModeCallBack);
                            }

                            mActionMode.setTitle(getSelectedItemsCount() + " " + mContext.getString(R.string.menu_selected));

                        } else {
                            mCheckList.set(pPosition, false);

                            setUncheckedBoxColor(lTask, lHolder);
                            setCheckedBoxVisibility(false, lHolder);
                            // applyRotation(false, lHolder.mCheckBoxUncheckedView, lHolder.mCheckBoxCheckedView, 0, 90);

                            if (mActionMode != null) {
                                if (getSelectedItemsCount() > 0) {
                                    mActionMode.setTitle(getSelectedItemsCount() + " " + mContext.getString(R.string.menu_selected));
                                } else {
                                    mActionMode.finish();
                                    mActionMode = null;
                                }
                            }
                        }
                    }
                };


                lHolder.mTextViewTitle.setText(lTask.getTitle());
                lHolder.mTextViewTime.setText(lTask.getFormattedEndTime());
                // lHolder.mCheckBoxUncheckedView.setChecked(mCheckList.get(pPosition));

                if (!mCheckList.get(pPosition)) {
                    setUncheckedBoxColor(lTask, lHolder);
                    setCheckedBoxVisibility(false, lHolder);
                } else {
                    setCheckedBoxVisibility(true, lHolder);
                }

                // Added to start CAB when a checkbox is clicked
                lHolder.mCheckBoxUncheckedView.setOnClickListener(lCheckBoxOnClickListener);
                lHolder.mCheckBoxCheckedView.setOnClickListener(lCheckBoxOnClickListener);

                break;
            case TYPE_SEPARATOR:
                lHolder.mTextViewTitle.setText((String) mListViewObjectsList.get(pPosition));
                break;
        }

        return convertView;
    }

    public void setCheckedBoxVisibility(Boolean isChecked, ViewHolder pHolder) {

        if (isChecked) {
            pHolder.mCheckBoxUncheckedView.setVisibility(View.GONE);
            pHolder.mCheckBoxCheckedView.setVisibility(View.VISIBLE);
        } else {
            pHolder.mCheckBoxCheckedView.setVisibility(View.GONE);
            pHolder.mCheckBoxUncheckedView.setVisibility(View.VISIBLE);
        }
    }

    public void setUncheckedBoxColor(Task pTask, ViewHolder pHolder) {

        if (pTask.getTaskGroupsIds() != null && pTask.getTaskGroupsIds().size() > 0) {

            for (TaskGroup lTaskgroup : mTaskGroupsList) {
                if (lTaskgroup.getId().equals(pTask.getTaskGroupsIds().getFirst())) {
                    pHolder.mCheckBoxUncheckedView.setText(lTaskgroup.getName().substring(0, 2));
                    GradientDrawable gd = (GradientDrawable) pHolder.mCheckBoxUncheckedView.getBackground();
                    gd.setColor(Color.parseColor(lTaskgroup.getColor()));
                    break;
                }
            }
        } else {
            GradientDrawable gd = (GradientDrawable) pHolder.mCheckBoxUncheckedView.getBackground();
            gd.setColor(mContext.getResources().getColor(R.color.cloud));
        }
    }

    public void addTask(Task pAddedTask) {

        if (!mListViewObjectsList.contains(pAddedTask)) { // La tâche existe et n'a pas été modifiée

            ArrayList<Object> lListViewObjectsListTemp = new ArrayList<Object>(mListViewObjectsList);
            for (Object lObj : lListViewObjectsListTemp) { // Je vérifie si la tâche ajoutée est déjà dans la liste mais a été mise à jour)

                if (lObj instanceof Task) { // C'est une tâche
                    Task lTask = (Task) lObj;

                    if (pAddedTask.getId().equals(lTask.getId())) {
                        mListViewObjectsList.remove(lTask); // Oui, je la supprime et l'ajouterai ensuite
                    }
                }
            }

            // Création d"une copie de la liste pour pouvoir ajouter des objets à la liste membre de la classe
            lListViewObjectsListTemp = new ArrayList<Object>(mListViewObjectsList);

            Boolean lNewHeaderRequired = true;

            for (Object lObj : lListViewObjectsListTemp) { // Je vérifie si la date a déjà été ajoutée aux headers

                if (lObj instanceof String) { // C'est une date
                    String lDate = (String) lObj;

                    if (pAddedTask.getFormattedEndDate().equals(lDate)) { // La date de la tâche est déjà présente dans la liste
                        lNewHeaderRequired = false;
                        break;
                    }
                }
            }

            // J'ajoute la date à la liste si nécessaire
            if (lNewHeaderRequired) {
                mListViewObjectsList.add(pAddedTask.getFormattedEndDate());
                mCheckList.add(false);
            }

            // J'ajoute la tâche à la liste
            mListViewObjectsList.add(pAddedTask);
            mCheckList.add(false);

            Collections.sort(mListViewObjectsList, new EndDateComparator());

            // Update the content of the listview
            notifyDataSetChanged();
        }

    }

    public void addMultipleTasks(LinkedList<Task> pTasksList) {
        for (Task lTask : pTasksList) {
            if (lTask != null) {
                addTask(lTask);
            }
        }
    }

    public void deleteMultipleTasks(ArrayList<Integer> pSelectedPositions) {

        // Tri de la liste pour supprimer les éléments du dernier au 1er
        List<Integer> pSortedSelectedPositions = new ArrayList<Integer>(pSelectedPositions);
        Collections.sort(pSortedSelectedPositions, Collections.reverseOrder());

        // Création de la liste des ID des tâches à supprimer
        ArrayList<Integer> lSelectedTasksIdList = new ArrayList<Integer>();

        // Obtention de l'ID de la tâche dans la BDD pour suppression
        for (Integer lSelectedPosition : pSortedSelectedPositions) {
            lSelectedTasksIdList.add(((Task) mListViewObjectsList.get(lSelectedPosition)).getId());
        }

        // Suppression de la tâche dans la BDD par ID
        deleteMultipleTasksInDb(lSelectedTasksIdList);

        // Suppression de la tâche de la liste
        for (int lSelectedPosition : pSortedSelectedPositions) {
            mListViewObjectsList.remove(lSelectedPosition);
            mCheckList.remove(lSelectedPosition);
        }

        // Suppression des headers plus nécessaires
        int i = 0;
        List<Integer> lIndexToDelete = new ArrayList<Integer>();
        while (i < mListViewObjectsList.size()) {
            if (i == mListViewObjectsList.size() - 1 && mListViewObjectsList.get(i) instanceof String) { // Si le dernier élément de la liste est une date
                // Je peux la supprimer
                lIndexToDelete.add(i);
            } else if (i < mListViewObjectsList.size() - 1 && mListViewObjectsList.get(i) instanceof String && mListViewObjectsList.get(i + 1) instanceof String) { // Ce sont deux dates consécutives
                // Je peux supprimer la 1ère
                lIndexToDelete.add(i);
            }
            i++;
        }

        // Je trie les index dans l'ordre inverse
        Collections.sort(lIndexToDelete, Collections.reverseOrder());

        // Puis je supprime les objets
        for (int lInt : lIndexToDelete) {
            mListViewObjectsList.remove(lInt);
        }

        notifyDataSetChanged();
    }

    public void deleteMultipleTasksInDb(ArrayList<Integer> pTasksIds) {

        String[] lTasksIds = new String[pTasksIds.size()];
        String lRequestPlaceholder = " IN (";

        int i = 0;
        for (Integer lIds : pTasksIds) {
            lTasksIds[i] = lIds.toString();

            if (i == 0) {
                lRequestPlaceholder += "?";
            } else {
                lRequestPlaceholder += ", ? ";
            }
            i++;
        }

        lRequestPlaceholder += ")";

        SqlReadQuery lSqlReadQuery = new SqlReadQuery();
        lSqlReadQuery.setTable(MyOrganizerDbContract.TaskEntry.TABLE_NAME);
        lSqlReadQuery.setSelection(MyOrganizerDbContract.TaskEntry.COLUMN_NAME_TASK_ID + lRequestPlaceholder);
        lSqlReadQuery.setSelectionArgs(lTasksIds);

        // Exécution de la requête
        DatabaseRemover lDatabaseRemover = new DatabaseRemover(mContext, mDbQueryCompletedListener);
        lDatabaseRemover.execute(lSqlReadQuery);
    }

    public void clearUnusedHeaders() {

        ArrayList<Integer> lUnusedHeaderIndexes = new ArrayList<Integer>();

        for (int i = 1; i < mListViewObjectsList.size(); i++) {
            if (mListViewObjectsList.get(i - 1) instanceof String && mListViewObjectsList.get(i) instanceof String) {
                lUnusedHeaderIndexes.add(i - 1);
            }
        }

        Collections.sort(lUnusedHeaderIndexes, Collections.reverseOrder());

        for (int i : lUnusedHeaderIndexes) {
            mListViewObjectsList.remove(i);
        }
    }

    public void addTaskGroup(TaskGroup pTaskGroup) {
        if (!mTaskGroupsList.contains(pTaskGroup)) {
            mTaskGroupsList.add(pTaskGroup);
        }
    }

    public void addMultipleTaskGroups(LinkedList<TaskGroup> pTaskGroupsList) {
        for (TaskGroup lTaskGroup : pTaskGroupsList) {
            if (lTaskGroup != null) {
                addTaskGroup(lTaskGroup);
            }
        }
    }

    public int getSelectedItemsCount() {

        int lCheckedItemCount = 0;

        for (Boolean lCheckStatus : mCheckList) {
            if (lCheckStatus)
                lCheckedItemCount++;
        }
        return lCheckedItemCount;
    }

    private void applyRotation(Boolean isFirst, View image1, View image2, float start, float end) {
        // Find the center of image
        final float centerX = image1.getWidth() / 2.0f;
        final float centerY = image1.getHeight() / 2.0f;

        // Create a new 3D rotation with the supplied parameter
        // The animation listener is used to trigger the next animation
        final Flip3d rotation = new Flip3d(start, end, centerX, centerY);
        rotation.setDuration(100);
        rotation.setFillAfter(true);
        rotation.setInterpolator(new AccelerateInterpolator());
        rotation.setAnimationListener(new DisplayNextView(isFirst, image1, image2));

        if (isFirst) {
            image1.startAnimation(rotation);
        } else {
            image2.startAnimation(rotation);
        }
    }

    public static class ViewHolder {
        CheckedTextView mCheckBoxUncheckedView;
        ImageView mCheckBoxCheckedView;
        TextView mTextViewTitle;
        TextView mTextViewTime;
    }
}
